Currently, memory of a computer is managed by a portion of the computer's operating system, generally referred to herein as a “memory manager.” When a computer program or other computing application (collectively referred to herein as an “application”) needs memory to perform operations, store data, or perform other functions, it requests the needed memory from the memory manager by providing the memory manager with an identification of the amount of memory needed. The memory manager, in return, allocates the requested amount of memory (referred to herein as a “block”), generates a block header that identifies and describes the block, and allows the requesting application access to the allocated memory. The block header generally includes several fields that are created by the memory manager and used by the memory manager to manage the memory. For example, fields of a block header may include a representation of the size of the block, a representation of a link to a previous block, block flags, unused bytes, and other internal block states.
The block size may include an identification of the size of the block that is allocated in response to a memory request. The flags field may be used by the memory manager to identify whether the block is busy, free, internally allocated, etc. The unused bytes may identify to the memory manager the bytes of the allocated block that are unused by the requesting application. In general, the fields of a block header are used by the memory manager and are intended to be private and modified only by the memory manager. Additionally, fields of a block header may vary in content, number, and size.
FIG. 1 is a block diagram of a portion of a memory region including two allocated blocks 101 and 102. Each block 101, 102 includes a block header that includes metadata, segmented into fields, that identifies the block. For example, block 102 includes a block header 103. Block header 103 includes metadata about the block 102 that is segmented into six fields 105, 107, 109, 111, 113, 115. Each of the fields 105, 107, 109, 111, 113, 115 include information that is used by the memory manager to manage block 102.
While the use of block headers make the management of data more efficient, it potentially exposes the computing system to attacks and unintended errors. For example, an application may request a particular amount of memory, be allocated that amount of memory, but write a larger amount of data than the allocated memory can hold. Thus, the following block header, and potentially a portion of the following data of the next block, in a memory region may be overwritten, thereby creating inconsistency that may lead to unpredictable results. Writing more data than there is allocated memory is referred to generally as “buffer overrun.” A buffer overrun may result from the inadvertent improper coding of an application. However, buffer overruns may be intentionally programmed in an effort to take control of a portion of memory and execute malicious code.
FIG. 2 is a block diagram of a memory region including two data blocks where malicious code has been written that results in a buffer overrun. Continuing with the region of memory discussed with respect to FIG. 1, an application may request a particular amount of memory that is needed to write data. In response, the memory manager may allocate a block of data 201 from a data region 200, generate a block header 216 for that block of data 201, and allow the requesting application to write to that block. As seen in FIGS. 1 and 2, the allocated block of data 201 may be adjacent in the memory region 200 to another allocated block of data 202, which also includes a block header 203 and a data block 217.
When access to the block 201 is granted, the application may inadvertently write more data than there is memory allocated, resulting in a buffer overrun that writes data over the block header 203 and possibly a portion of the data block 217 of the adjacent memory block 201. As some of the overwritten block header fields 205, 207, 209, 211, 213, 215 are used by the memory manager, it may notice the inconsistencies and avoid unpredictable results by performing actions like raising exceptions, terminating the application, logging an error, etc.
Creators of malicious code may attempt to hide an intentional buffer overrun from the memory manager so that the overrun is not detected or prevent the application from crashing due to inconsistencies in an effort to take control over the application. One technique for hiding a buffer overrun is attempting to restore particular fields of the block header. In particular, creators of malicious code can predict which fields of a block header may result in the memory manager detecting a buffer overrun and terminate the application before the malicious code is able to take control. Using that knowledge, good values may be predicted for those fields and data may be included in the buffer overrun at the location of those fields that will attempt to restore those fields. For example, if a writer of malicious code is able to predict that the memory manager will detect a buffer overrun if field 3 209 and field 4 211 are changed, based on that knowledge, the buffer overrun can be created such that the data written to the location of those fields is the same as the data originally included in those fields.
If the malicious code is successful in hiding a buffer overrun by predicting good values for particular fields 209 and 211, it may be able to modify other fields in the block header 205, 207, 213, and 219 so that when those fields are accessed by the memory manager, the malicious code can take control of the application and potentially cause an intended harmful result to the computer, such as executing a piece of malicious code in a target application.
Accordingly, there is a need for a system and method that may be used to detect attempted buffer overruns before they can be exploited by malicious code. Such a system and method would be beneficial in protecting a computer from malicious attacks, as well as provide the ability to detect inadvertent programming flaws early in application development, without having to pay the overhead of other debugging methods that affect performance, memory usage, etc.